package com.ansion.basedb.dao;

import android.content.ContentValues;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.ansion.basedb.dao.entity.FtsUserEntity;
import com.ansion.basedb.dao.entity.GroupUserEntity;
import com.ansion.basedb.dao.entity.UserTables;
import com.ansion.basedb.dao.helper.ContactsHelper;
import com.ansion.basedb.dao.helper.FtsIndexHistoryHelper;
import com.ansion.basedb.dao.helper.UserIndexHistoryHelper;
import com.ansion.basedb.dao.model.ContactsModel;
import com.ansion.basedb.dao.model.GroupModel;
import com.ansion.basedb.dao.model.UserModel;
import com.ansion.basedb.database.DatabaseTools;
import com.ansion.basedb.database.IDatabaseManager;
import com.ansion.basedb.database.SqlQueryUtil;
import com.ansion.basedb.database.sql.SQLColumn;
import com.ansion.basedb.database.sql.SQLJoinType;
import com.ansion.basedb.database.sql.SQLRow;
import com.ansion.basedb.database.sql.SearchParams;
import com.ansion.basedb.storage.StorageSdk;
import com.ansion.basetool.preconditions.Preconditions;
import com.ansion.constant.BConstant;
import com.ansion.log.VLog;
import com.ansion.utils.ArrayUtil;
import com.ansion.utils.BooleanCallback;
import com.ansion.utils.ContactUtil;
import com.ansion.utils.ThreadUtil;
import com.ansion.utils.ValueSafeTransfer;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * created by zhaoyuntao
 * on 07/12/2023
 */
public class UserFTSHelper {

    public static void indexUser(Map<Long, ContactsModel> contactsModels) {
        if (StorageSdk.getMainDB() == null) {
            return;
        }
        if (!StorageSdk.getMainDB().isEncryptDB()) {
            return;
        }
        if (ArrayUtil.isEmpty(contactsModels))
            return;
        //查出所有在UserModel表的UserModel，然后更新索引
        ThreadUtil.runSingleTask(() -> {
            String sql = " SELECT " + SqlQueryUtil.buildSqlSelect(UserModel.kColumnName_UserId, UserModel.kColumnName_NickName, UserModel.kColumnName_UpdateTime)
                    + " FROM " + DatabaseTools.getTableName(UserModel.class)
                    + " WHERE " + SqlQueryUtil.buildSqlInForNumberList(UserModel.kColumnName_UserId, contactsModels.keySet());
            List<SQLRow> list = StorageSdk.getMainDB().select(sql);
            Map<String, FtsUserEntity> userMap = new HashMap<>();
            ValueSafeTransfer.iterateAll(list, (position, sqlRow) -> {
                long uid = sqlRow.getAsLong(UserModel.kColumnName_UserId);
                String nickName = sqlRow.getAsString(UserModel.kColumnName_NickName);
                long updateTime = sqlRow.getAsLong(UserModel.kColumnName_UpdateTime);
                String userId = String.valueOf(uid);
                if (!canCreateUserIndex(userId, updateTime))
                    return;
                FtsUserEntity ftsUserEntity = generateFtsUserBeanForUI(userId, nickName, ContactsHelper.getContact(uid));//每次都重新从Contacts内存缓存中重新取一下
                userMap.put(ftsUserEntity.getUid(), ftsUserEntity);
            });
            compareAndIndexUser(userMap, null);
        });

    }

    public static void indexUser(@NonNull UserModel userModel) {
        indexUser(Collections.singletonList(userModel));
    }

    public static void indexUser(@NonNull List<UserModel> userModels) {
        if (StorageSdk.getMainDB() == null) {
            return;
        }
        if (!StorageSdk.getMainDB().isEncryptDB()) {
            return;
        }
        ThreadUtil.runSingleTask(() -> {
            realIndexUser(userModels);
        });
    }

    private static boolean canCreateUserIndex(String userId, long updateTime) {
        //1.过滤掉不是用户的
        if (!ContactUtil.isUser(userId)) {
            return false;
        }

        //2.过滤掉自己
//        if (ContactUtil.isSelf(userId))
//            return false;
        //2.正在同步索引的时候过滤掉还未同步索引的User
        if (!UserIndexHistoryHelper.userIndexComplete()) {
            long userIndexProcessTime = FtsIndexHistoryHelper.getFirstInstallSystemTime();
            if (userIndexProcessTime <= 0 || updateTime < userIndexProcessTime) {
                VLog.FileLog.i("TAG_SEARCH_FTS", "current user first index is not finish,uid:%s", userId);
                return false;
            }
        }
        return true;
    }

    private static void realIndexUser(@NonNull List<UserModel> userModels) {
        Map<String, FtsUserEntity> userMap = new HashMap<>();
        ValueSafeTransfer.iterateAll(userModels, (position, userModel) -> {
            String userId = String.valueOf(userModel.getUserId());
            if (!canCreateUserIndex(userId, userModel.getUpdateTime()))
                return;
            FtsUserEntity ftsUserEntity = generateFtsUserBeanForUI(userId, userModel.getNickName(), ContactsHelper.getContact(userModel.getUserId()));
            userMap.put(ftsUserEntity.getUid(), ftsUserEntity);
        });
        compareAndIndexUser(userMap, null);
    }

    private static FtsUserEntity generateFtsUserBeanForUI(String userId, String nickName, ContactsModel contactsModel) {
        FtsUserEntity ftsUserEntity = new FtsUserEntity().setUid(userId).setNickName(nickName);
        if (contactsModel != null) {
            ftsUserEntity.set(contactsModel.getFirstName(), contactsModel.getMiddleName(), contactsModel.getLastName());
            ftsUserEntity.setType(FtsUserEntity.UserType.TYPE_CONTACT);
        }
        return ftsUserEntity;
    }

    public static void compareAndIndexUser(Map<String, FtsUserEntity> userMap, BooleanCallback callback) {
        if (ArrayUtil.isEmpty(userMap)) {
            if (callback != null)
                callback.onResult(true);
            return;
        }
        IDatabaseManager mainDB = StorageSdk.getMainDB();
        if (mainDB == null) {
            if (callback != null)
                callback.onFail(new RuntimeException("mainDB is null"));
            return;
        }
        String query = "SELECT " + SqlQueryUtil.buildSqlSelect(BConstant.MIGRATE.KEY_ROW_ID, UserTables.FTS_USER.KEY_UID, UserTables.FTS_USER.KEY_TYPE, UserTables.FTS_USER.KEY_EXTRA)
                + " FROM " + UserTables.FTS_USER.TABLE_NAME + " WHERE " + SqlQueryUtil.buildSqlInForStringList(UserTables.FTS_USER.KEY_UID, userMap.keySet());
        List<FtsUserEntity> updateUsers = new ArrayList<>();
        List<SQLRow> rows = mainDB.select(query);
        ValueSafeTransfer.iterateAll(rows, (position, sqlRow) -> {
            long rowId = sqlRow.getAsLong(BConstant.MIGRATE.KEY_ROW_ID);
            String uid = sqlRow.getAsString(UserTables.FTS_USER.KEY_UID);
            int type = sqlRow.getAsInteger(UserTables.FTS_USER.KEY_TYPE);
            String extra = sqlRow.getAsString(UserTables.FTS_USER.KEY_EXTRA);
            //比对数据是否有变更
            FtsUserEntity beanForUI = new FtsUserEntity();
            beanForUI.setUid(uid).setRowId(rowId).setType(type).readExtraJson(extra);
            FtsUserEntity currentUser = userMap.remove(uid);
            if (currentUser != null && !beanForUI.contentIsSame(currentUser)) {
                currentUser.setRowId(rowId);//这行不能少，否则就是直接插入了而非替换
                updateUsers.add(currentUser);
            }
        });
        //userMap剩余的就是纯新增的
        List<FtsUserEntity> newUsers = ValueSafeTransfer.transformList(userMap.values(), (position, t) -> t);
        if (!newUsers.isEmpty() || !updateUsers.isEmpty()) {//有数据，需要写数据库
            mainDB.execWithTransaction(() -> {
                if (!newUsers.isEmpty()) {
                    ValueSafeTransfer.iterateAll(newUsers, (position, ftsUserBeanForUI) -> {
                        VLog.i("TAG_SEARCH_FTS", "insert user:%s,values:%s", ftsUserBeanForUI.getUid(), ftsUserBeanForUI.getContentValues());
                        long ret = mainDB.getDatabase().insert(UserTables.FTS_USER.TABLE_NAME, null, ftsUserBeanForUI.getContentValues());
                        if (ret == -1) {
                            throw new RuntimeException("insert new user error");
                        }
                    });
                }
                if (!updateUsers.isEmpty()) {
                    ValueSafeTransfer.iterateAll(updateUsers, (position, ftsUserBeanForUI) -> {
                        ContentValues values = ftsUserBeanForUI.getContentValues();
                        VLog.i("TAG_SEARCH_FTS", "replace user:%s,rowId:%s,values:%s", ftsUserBeanForUI.getUid(), ftsUserBeanForUI.getRowId(), values);
                        long ret = mainDB.getDatabase().replace(UserTables.FTS_USER.TABLE_NAME, null, values);
                        if (ret == -1) {
                            throw new RuntimeException("replace old user error");
                        }
                    });
                }
            }, new BooleanCallback() {
                @Override
                public void onResult(boolean result) {
                    VLog.i("TAG_SEARCH_FTS", "indexUser newUsers:%d,updateUsers:%d,ret:%b", newUsers.size(), updateUsers.size(), result);
                    if (callback != null)
                        callback.onResult(result);
                }

                @Override
                public void onFail(Throwable tr) {
                    if (callback != null)
                        callback.onFail(tr);
                }
            });
        } else {
            if (callback != null)
                callback.onResult(true);
        }

    }

    /***
     *批量创建索引
     * 如果isReplace=true则是先查再存，为false则为直接插入
     */
    public static void indexUserOnly(@NonNull List<FtsUserEntity> list, @Nullable BooleanCallback callback) {
        if (ArrayUtil.isEmpty(list)) {
            if (callback != null)
                callback.onResult(true);
        } else
            StorageSdk.getMainDB().replace(UserTables.FTS_USER.TABLE_NAME, ValueSafeTransfer.transformList(list, (p, v) -> v.writeToSQLRow()), result -> {
                        if (callback != null)
                            callback.onResult(result);
                        VLog.FileLog.i("TAG_SEARCH_FTS", "indexUser %s,ret:%b", VLog.OPEN_LOG ? ArrayUtil.combine(list) : list.size(), result);
                    }
            );


    }


    /***
     * 拉到最新的groupFullInfo，lastRequestTime必定比分界线大，全量存，不用去管原来是否有
     */
    public static void indexGroupMembers(@NonNull List<GroupModel> groups, @Nullable BooleanCallback callback) {
        List<GroupUserEntity> ftsGroups = new ArrayList<>();
        ValueSafeTransfer.iterateAll(groups, (position, g) -> {
            if (TextUtils.isEmpty(g.getUid()))
                return;
            ValueSafeTransfer.iterateAll(g.getGroupMemberUidList(), (p, memberUid) -> {
                if (!TextUtils.isEmpty(memberUid))
                    ftsGroups.add(new GroupUserEntity().setGid(g.getUid()).setMemberUid(memberUid));
            });

        });
        indexGroupMemberOnly(ftsGroups, callback);
    }

    public static void removeGroupMembers(GroupModel groupModel, List<Long> members) {
        ThreadUtil.runSingleTask(() -> {
            if (!groupMemberIndexFinish(groupModel)) {
                VLog.FileLog.i("TAG_SEARCH_FTS", "removeGroupMembers for %s, but group not indexFinish,return", groupModel.getUid());
                return;
            }
            deleteGroupMember(groupModel.getUid(), ValueSafeTransfer.transformList(members, (p, v) -> String.valueOf(v)));
        });

    }

    public static void addGroupMembers(GroupModel groupModel, List<Long> members) {
        ThreadUtil.runSingleTask(() -> {
            if (!groupMemberIndexFinish(groupModel)) {
                VLog.FileLog.i("TAG_SEARCH_FTS", "addGroupMembers for %s, but group not indexFinish,return", groupModel.getUid());
                return;
            }
            indexGroupMemberOnly(ValueSafeTransfer.transformList(members, (position, uid) -> new GroupUserEntity().setGid(groupModel.getUid()).setMemberUid(String.valueOf(uid))), null);
        });
    }

    private static boolean groupMemberIndexFinish(GroupModel groupModel) {
        if (UserIndexHistoryHelper.groupIndexComplete())//整个群索引昨晚则可以更新
            return true;

        if (FtsIndexHistoryHelper.getFirstInstallSystemTime() > 0 && groupModel.getLastRequestTime() > FtsIndexHistoryHelper.getFirstInstallServerTime()) {//时间大于分界线时间，group可以更新
            return true;
        }
        //时间小于等于分界线时间，则要看sp存的索引同步状态是否结束
        return UserIndexHistoryHelper.groupIndexFinish(groupModel.getUid());
    }


    public static void indexGroupMemberOnly(@NonNull List<GroupUserEntity> groupMembers, @Nullable BooleanCallback callback) {
        if (!ArrayUtil.isEmpty(groupMembers))
            StorageSdk.getMainDB().replace(UserTables.GROUP_USER.TABLE_NAME, ValueSafeTransfer.transformList(groupMembers, (p, v) -> v.writeToSQLRow()), new BooleanCallback() {
                @Override
                public void onResult(boolean result) {
                    if (callback != null)
                        callback.onResult(result);
                    VLog.FileLog.i("TAG_SEARCH_FTS", "indexGroupMember %s,ret:%b", VLog.OPEN_LOG ? ArrayUtil.combine(groupMembers) : groupMembers.size(), result);
                }

                @Override
                public void onFail(Throwable tr) {
                    if (callback != null)
                        callback.onFail(tr);
                }
            });
        else {
            if (callback != null)
                callback.onResult(true);
        }

    }


    public static void deleteUserIndex(@NonNull String uid) {
        VLog.i("TAG_SEARCH_FTS", "deleteUserIndex %s ", uid);
        String sql = "DELETE FROM " + UserTables.FTS_USER.TABLE_NAME + " WHERE " + SqlQueryUtil.buildSqlStringEqual(UserTables.FTS_USER.KEY_UID, uid);
        StorageSdk.getMainDB().execSQL(sql);
        sql = "DELETE FROM " + UserTables.GROUP_USER.TABLE_NAME + " WHERE " + SqlQueryUtil.buildSqlStringEqual(UserTables.GROUP_USER.KEY_UID, uid);
        StorageSdk.getMainDB().execSQL(sql);
    }

    /**
     * 当用户删除账户时，应该把这个用户从群成员索引中移除。
     */
    public static void deleteUserIndex(@NonNull List<String> uidList) {
        Preconditions.checkNotEmpty(uidList);
        StorageSdk.getMainDB().execWithTransaction(() -> {
            String sql = "DELETE FROM " + UserTables.FTS_USER.TABLE_NAME + " WHERE " + SqlQueryUtil.buildSqlInForStringList(UserTables.FTS_USER.KEY_UID, uidList);
            StorageSdk.getMainDB().execSQL(sql);
            sql = "DELETE FROM " + UserTables.GROUP_USER.TABLE_NAME + " WHERE " + SqlQueryUtil.buildSqlInForStringList(UserTables.GROUP_USER.KEY_UID, uidList);
            StorageSdk.getMainDB().execSQL(sql);
        }, result -> {
            VLog.FileLog.i("TAG_SEARCH_FTS", "deleteUserIndex %s,ret:%b ", ArrayUtil.combine(uidList), result);
        });

    }

    public static void deleteGroupAllMembers(@NonNull String gid) {
        VLog.i("TAG_SEARCH_FTS", "deleteGroupAllMembers [%s] ", gid);
        String sql = "DELETE FROM " + UserTables.GROUP_USER.TABLE_NAME + " WHERE " + SqlQueryUtil.buildSqlStringEqual(UserTables.GROUP_USER.KEY_GID, gid);
        StorageSdk.getMainDB().execSQL(sql);
    }

    public static void deleteGroupMember(@NonNull String gid, @NonNull Collection<String> userIds) {
        if (VLog.OPEN_LOG) {
            VLog.i("TAG_SEARCH_FTS", "deleteGroupMember [%s] %s", gid, ArrayUtil.combine(userIds));
        }
        String sql = "DELETE FROM " + UserTables.GROUP_USER.TABLE_NAME + " WHERE " + SqlQueryUtil.buildSqlStringEqual(UserTables.GROUP_USER.KEY_GID, gid)
                + " AND " + SqlQueryUtil.buildSqlInForStringList(UserTables.GROUP_USER.KEY_UID, userIds);
        StorageSdk.getMainDB().execSQL(sql);
    }

    public static void debugDeleteAllFTSUserIndex() {
        String sql = "DELETE FROM " + UserTables.FTS_USER.TABLE_NAME;
        StorageSdk.getMainDB().execSQL(sql);
        sql = "DELETE FROM " + UserTables.GROUP_USER.TABLE_NAME;
        StorageSdk.getMainDB().execSQL(sql);

    }

    /**
     * 我们的产品需求上面没有搜索全量用户的场景，所以这个方法暂时没用到。
     * 会搜索用户的场景有3个：联系人搜索、群搜索、群内成员搜索。
     */
    public static List<FtsUserEntity> searchUsers(@NonNull SearchParams params) {
        int limit = params.getLimit();
        int pageNumber = params.getPageNumber();
        int offset = limit * pageNumber;
        String searchContent = params.getSearchContent();
        boolean isLike = searchContent.length() < 3;
        String matchParam = isLike ? SqlQueryUtil.buildSqlLike(UserTables.FTS_USER.KEY_CONTENT, searchContent) : SqlQueryUtil.buildSqlMatch(UserTables.FTS_USER.KEY_CONTENT, searchContent);
        String sqlQuery = "SELECT * FROM " + UserTables.FTS_USER.TABLE_NAME + " WHERE "
                + matchParam + SqlQueryUtil.buildSqlLimit(limit, offset);
        return StorageSdk.getMainDB().select(FtsUserEntity::new, sqlQuery);
    }


    public static List<GroupUserEntity> searchGroupMembers(@NonNull SearchParams params) {
        if (StorageSdk.getMainDB() == null) {
            return Collections.emptyList();
        }

        if (!StorageSdk.getMainDB().isEncryptDB()) {
            return Collections.emptyList();
        }
        if (TextUtils.isEmpty(params.getSearchContent())) {
            return Collections.emptyList();
        }
        int limit = params.getLimit();
        int pageNumber = params.getPageNumber();
        int offset = limit * pageNumber;
        String searchContent = params.getSearchContent();
        boolean isLike = searchContent.length() < 3;
        String matchParam = isLike ? SqlQueryUtil.buildSqlLike(UserTables.FTS_USER.KEY_CONTENT, searchContent) : SqlQueryUtil.buildSqlMatch(UserTables.FTS_USER.KEY_CONTENT, searchContent);
        // 搜索走FTSUser与GroupUser联表查询
        String sql = " SELECT " + SqlQueryUtil.buildSqlSelect(
                SQLColumn.getColumnName(UserTables.FTS_USER.TABLE_NAME, UserTables.FTS_USER.KEY_UID),
                SQLColumn.getColumnName(UserTables.FTS_USER.TABLE_NAME, UserTables.FTS_USER.KEY_EXTRA),
                SQLColumn.getColumnName(UserTables.FTS_USER.TABLE_NAME, UserTables.FTS_USER.KEY_TYPE),
                SQLColumn.getColumnName(UserTables.GROUP_USER.TABLE_NAME, UserTables.GROUP_USER.KEY_GID))
                + " FROM " + UserTables.FTS_USER.TABLE_NAME +
                SqlQueryUtil.buildSqlJoin(SQLJoinType.TYPE_INNER_JOIN, UserTables.FTS_USER.TABLE_NAME, UserTables.FTS_USER.KEY_UID,
                        UserTables.GROUP_USER.TABLE_NAME, UserTables.GROUP_USER.KEY_UID)
                + " WHERE " + matchParam
                + " GROUP BY " + UserTables.GROUP_USER.TABLE_NAME + "." + UserTables.GROUP_USER.KEY_GID
                + SqlQueryUtil.buildSqlLimit(limit, offset);
        List<SQLRow> rows = StorageSdk.getMainDB().select(sql);
        long current = System.currentTimeMillis();
        List<GroupUserEntity> list = ValueSafeTransfer.transformList(rows, (position, t) -> {
            String gid = t.getAsString(UserTables.GROUP_USER.KEY_GID);
            String uid = t.getAsString(UserTables.FTS_USER.KEY_UID);
            if (TextUtils.isEmpty(gid) || TextUtils.isEmpty(uid))
                return null;
            GroupUserEntity member = new GroupUserEntity();
            member.setGid(gid).setMemberUid(uid);
            FtsUserEntity user = new FtsUserEntity();
            user.readExtraJson(t.getAsString(UserTables.FTS_USER.KEY_EXTRA));
            user.setUid(uid);
            user.setType(t.getAsInteger(UserTables.FTS_USER.KEY_TYPE));
            member.setUserBeanForUI(user);
            return member;
        });
        long cost = System.currentTimeMillis() - current;

        if (VLog.OPEN_LOG) {
            VLog.i("TAG_SEARCH_FTS", "searchGroupMembers searchContent:%s,[%d,%d] cost %d ms", searchContent, limit, offset, cost);
        }

        return list;
    }

}
